﻿#ifndef _OI_PLSCANNERUTIL_ALGORITHMS_HPP_
#define _OI_PLSCANNERUTIL_ALGORITHMS_HPP_
#define _CRT_SECURE_NO_WARNINGS

#include "PLScannerUtil.hpp"
#include <QtCore/QtCore>
#include <QtGui/QtGui>
#include <opencv2/opencv.hpp>

#include "Base/OiGlobals.hpp"
#include "Base/OiDefines.hpp"
#include "Algo/OiAlgo.hpp"
#include "Geom/OiGeom.hpp"
#include "Geom/OiCgal.hpp"


namespace Oi
{
    namespace PLScannerUtil
    {
        double OI_PLSCANNER_UTIL_API CalcDistance(const QPointF& p1, const QPointF& p2);
        double OI_PLSCANNER_UTIL_API CalcDistance(const QPointF& p, const QLineF& l);
        QPointF OI_PLSCANNER_UTIL_API perpendicularFoot(const QPointF& p, const QLineF & l);
        double OI_PLSCANNER_UTIL_API judgeSide(const QPointF& p1, const QPointF& p2, const QLineF & l);

        bool OI_PLSCANNER_UTIL_API DFT_1D(const cv::Mat line, cv::Mat_<float>& amp, cv::Mat_<float>& phase);
        void OI_PLSCANNER_UTIL_API reduceAvg(const cv::Mat src, cv::Mat_<float>& dst, int direct = 1, bool fillBlock = true);
        void OI_PLSCANNER_UTIL_API interpolation(const cv::Mat src, cv::Mat index, cv::Mat& dst, int direct = 0);
        class OI_PLSCANNER_UTIL_API FindPointsF
        {
        public:
            enum Method
            {
                Head,
                Tail,
                Steepest,
                AllForeward,
                AllBackward,
                AllDescending,
                AllAscending
            };

            enum Interp
            {
                Nearest,
                Bilinear,
                Bicubic
            };

            enum Transition
            {
                Both,
                L2D, // Light to Dark
                D2L  // Dark to Light
            };

        public:
            class Node : public Base::Tuple<Geom::Point2f, int, int>
            {
            public:
                Node(const Geom::Point2f& point, int transition, int amplitude) : Base::Tuple<Geom::Point2f, int, int>(point, transition, amplitude)
                {
                }

            public:
                const Geom::Point2f& point() const
                {
                    return std::get<0>(*this);
                }

                int transition() const
                {
                    return std::get<1>(*this);
                }

                int amplitude() const
                {
                    return std::get<2>(*this);
                }
            };

        public:
            typedef typename Base::List<Node> ResultType;

        public:
            static int execute(const Geom::Image& source, const Geom::Segment2f& profile, int sampleWidth, double sigma, double minAmp, double maxAmp, int extend, int method, int interp, int transition, ResultType& points);
        };
        class OI_PLSCANNER_UTIL_API FindPointsD
        {
        public:
            enum Method
            {
                Head,
                Tail,
                Steepest,
                AllForeward,
                AllBackward,
                AllDescending,
                AllAscending
            };

            enum Interp
            {
                Nearest,
                Bilinear,
                Bicubic
            };

            enum Transition
            {
                Both,
                L2D, // Light to Dark
                D2L  // Dark to Light
            };

        public:
            class Node : public Base::Tuple<Geom::Point2d, int, int>
            {
            public:
                Node(const Geom::Point2d& point, int transition, int amplitude) : Base::Tuple<Geom::Point2d, int, int>(point, transition, amplitude)
                {
                }

            public:
                const Geom::Point2d& point() const
                {
                    return std::get<0>(*this);
                }

                int transition() const
                {
                    return std::get<1>(*this);
                }

                int amplitude() const
                {
                    return std::get<2>(*this);
                }
            };

        public:
            typedef typename Base::List<Node> ResultType;

        public:
            static int execute(const Geom::Image& source, const Geom::Segment2d& profile, int sampleWidth, double sigma, double minAmp, double maxAmp, int extend, int method, int interp, int transition, ResultType& points);
        };
        int OI_PLSCANNER_UTIL_API FindLow32(const Geom::ImageT<float>& source, const Geom::Segment2f& profile, int sampleWidth, double sigma, int minAmp, int maxAmp, int extend, int method, int interp, FindPointsF::ResultType& points);
        bool OI_PLSCANNER_UTIL_API intersect(QLineF& line, QList<QPointF>& segments, QPointF& point);
        bool OI_PLSCANNER_UTIL_API intersect(QLineF& line1, QLineF& line2, QPointF& point);
        double OI_PLSCANNER_UTIL_API y_at_profile(const QList<QPointF> profile, const double x);

        float OI_PLSCANNER_UTIL_API medianX(const QList<QPointF>& points);
        float OI_PLSCANNER_UTIL_API medianY(const QList<QPointF>& points);
        float OI_PLSCANNER_UTIL_API medianV(const QList<double>& values);

        void OI_PLSCANNER_UTIL_API calCPCPK(QList<double> values, double& cp, double& cpk, const double tolMax, const double tolMin);
        void OI_PLSCANNER_UTIL_API calFPY(QList<double> values, double& okRatio, const double tolMax, const double tolMin);

        void OI_PLSCANNER_UTIL_API filter(QList<QPointF>& ps, bool sideCorrect = true, double thresh = 0.1,  bool lpf = false, int filterLen = 50);

    }
}
#endif



